perm filename MBOX.DGL[UP,DOC]14 blob sn#372498 filedate 1978-08-06 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00019 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	Abstract
C00004 00003	MUSBOX help message.
C00013 00004	Samson box output
C00025 00005	Bells and whistles for MUSBOX output.
C00040 00006	The scanner-parser file scanner.
C00044 00007	Setting timing variables for Samson box output:
C00047 00008	PRINT statement, strings, RDNUM.
C00049 00009	Even less about loading Samson box command streams
C00061 00010	Loading your own instruments.
C00067 00011	Loading MUSBOX
C00071 00012	The essential ingredients in an instrument file
C00074 00013	Things available to instrumens from MBOX.
C00075 00014	What each instrument is handed by the scanner
C00082 00015	GOSC GOSCVF SHAPE LINGER GEN MOD MIX RANDOM FILTER REV GENFM1 GENFM3 SPACE
C00091 00016	That's about all you need to know.  If you have any questions, 
C00092 00017	APPENDIX - Running out of Sum_Memory Locations on the Generator Side [JEG]
C00098 00018	If you want your instrument to have a default F1 function like MUSCMP,
C00100 00019	If you want to preset the P fields in MBOX to default values,
C00102 ENDMK
C⊗;
Abstract

This describes the program MUSBOX, written by Gareth Loy,
which takes PLAY  block code suitable  for MUSCMP, such  as the output  of
SCORE or whatever and translates it  into a binary command  stream
for the Samson box.

The program is made to resemble  MUSCMP somewhat, with  some
additions and changes, as the hardware environment requires.

The system version of this program is SYS:MBOX.
MUSBOX help message.

(This is actually more like a helpless message.)

If MUSBOX sent you here, it is likely that what you said to MUSBOX was not
correct.  Pay particular attention to the error message that invoked the
error.  If it doesn't make sense to you, find someone to whom it does.
There is currently no listing of error messages and what they likely mean,
because it would change daily (sigh).  In essence, punt.

What follows is a list of available instruments in MUSBOX,
their parameters, and a sample call of each.

SAMINS INSTRUMENTS

The following instruments are loaded into the system MUSBOX (6/28/78);
The first word on each line is the formal name of the instrument that
MUSBOX refers to it by, the second one, in quotes, is the name the user
refers to it by when passing a PLAY list to MUSBOX.

MixMod,"MIX"  
RevMod,"REV"
FiltMod,"FLT"
Reverb,"REVERB"
Addit1,"ADDIT1"
Addit2,"ADDIT2",64
Simp,"SIMP"
SpaceSimp,"SPACESIMP"
SpaceFM,"SPACEFM"
VibFm,"VIBFM"
FormFm,"FORMFM"
SynthOsc,"TOOT"

INSTRUMENT PARAMETERS

Their parameters are as follows:
 
∂ MIX - Multiply two signals by constant factors between 0 and 8.;
P1	P2	P3	P4	P5	P6	P7
Beg	Dur   Factor1 Factor2 InLoc1  InLoc2  OutLoc; 


∂ REV - Reverberator. Can be all-pass or comb.
To make an allpass, set g1←-g0←G;
P1	P2	P3	P4	P5	P6	P7
Beg	Dur   Length  Gain1   Gain2   InLoc   OutLoc; 


∂ FLT - Does one or two pole or zero fixed character filtering.
P1	P2	P3	P4	  P5	     P6	      P7      P8
Beg	Dur    Freq     R    Second_Order  All_Pole  InLoc  OutLoc;


∂ REVERB - Complete reverberator. Can be all-pass or comb.
(Calls 11 modifiers, 4 modifier sum memory locations, 11 delay lines.)
P1	P2
Beg	Dur ;


∂ Addit1: Frequency ratio and relative amplitude for each harmonic, plus
point source location capability in angle and distance;
P1	P2	P3	P4	P5	P6	P7	P8	P9	P10
Beg    Dur    Freq      Amp   AmpFun   AtPt   AtDur    DcPt    DcDur    Deg     

P11    P12     P13      P14          P15        P16         P17         P18
Dis   PcRev NumHarms HarmRatio[1] HarmAmp[1] HarmRatio[2] HarmAmp[2] ........ ;


∂ Addit2: Frequency ratio, relative amplitude, and amp function for each harmonic,
plus point source location capability in angle and distance;
P1	P2	P3	P4	P5	P6	P7	P8	P9	P10
Beg    Dur    Freq      Amp     -      AtPt   AtDur    DcPt    DcDur    Deg     

P11    P12     P13      P14          P15        P16           P17         P18
Dis   PcRev NumHarms HarmRatio[1] HarmAmp[1] HarmAmpFun[1] HarmRatio[2] HarmAmp[2]

P19            P20.......
HarmAmpFun[2]............ ;


∂ Simp This instrument is a simple oscillator.
P1	P2	P3	P4	P5	P6 	P7	P8	P9
Beg    Dur    Freq    Amp    Ampfun     OutaAmp OutB   OutC    OutD
(default values in MUSBOX are 0 .5 A 1 f1 1 0 0 0)


∂ SpaceSimp This instrument is a simple oscillator with independent attack and decay
controls on the envelopes, and a point source location capability in ang and distance;
P1	P2	P3	P4	P5	P6	P7	P8	P9	P10
Beg    Dur    Freq      Amp   AmpFun   AtPt   AtDur    DcPt    DcDur    Deg     

P11   P12 
Dis   PcRev;


∂ SpaceFM  This instrument is a simple FM type with independent attack and decay
controls on the envelopes, and a point source location capability in ang and distance;
P1	P2	P3	P4	P5	P6	P7	P8	P9	P10
Beg    Dur    Freq      Amp   AmpFun   AtPt   AtDur    DcPt    DcDur    Deg

P11	P12	P13	P14	P15	P16
Dis    PcRev  ModRatio IndxFun Indx0   Indx1;


∂ VibFm  This instrument is a simple FM type with independent attack and decay
controls on the envelopes, vibrato, and a point source location capability in 
ang and distance;
P1	P2	P3	P4	P5	P6	P7	P8	P9	P10
Beg    Dur    Freq     Amp    AmpFun   AtPt   AtDur    DcPt    DcDur    Deg

P11	P12	P13	P14	P15	P16	P17	P18
Dis    PcRev  ModRatio IndxFun Indx0   Indx1	VibPc	VibRate


∂ FormFM  This instrument is a double carrier FM type with independent attack and
decay controls on the envelopes, vibrato, and a point source location capability
in ang and distance;
P1	P2	P3	P4	P5	P6	P7	P8	P9	P10
Beg    Dur    Freq     Amp    AmpFun   AtPt   AtDur    DcPt    DcDur    Deg

P11   P12     P13      P14     P15    P16    P17    P18     P19		P20
Dis  PcRev  ModRatio IndxFun  Indx0  Indx1  VibPc VibRate  FormFreq  AmpScale

P21
IndxScale;


∂ TOOT - reads synth function, fixed frequency, seg record variable amplitude;
P1	P2	P3	P4	P5	P6	P7	P8	P9	P10
beg    dur     freq     amp    ampfun  synthfun outa% outb%  outc%     outd%


SAMPLE CALLS
MIX,REV, and FLT are really pieces of instruments. To see how they are
used see REVERB or any of the instruments which use LOCATION.

A sample play file might be:

RECORD TEST.FUN[SAM,BIL];
DEBUG←DEBUG_INSTRUMENTS;
PLAY;
REVERB 0 10;
TOOT 0 1 220 1 F2 F16;
simp 1 1 220 1 f2 0 .5 .5 0;
Addit1 2 1 220 1 F2 0 0 0 0 180 1.5 .05 4
	1.41 1 2.17 .5 3.33 .33 4.76 .25;
addit2 3 1 110 1 f2 0 0 0 0 45 1 .05 4
	1 1 f12
	1.41 .5 f12
	2.17 .33 f14
	5.22 .3 f15;
Vibfm 4 1 256 .7 f2 0 0 0 0 45 1 .05
	1.2 f2 0 2 .20 6;
Formfm 5 1 256 .7 f2 0 0 0 0 45 1 .05
	1.2 f2 0 2 .20 6 1000 .4 .4;
spacefm 6 1 AS .7 f3 0 0 0 0 160 2 .05
	1.2 f2 0 2;
spaceSIMP 7 1 AS .7 f2 0 0 0 0 160 2 .05;
FINISH;
Samson box output
Here's an  example  of  getting  Samson  box  output.
There  is code for
Samson instruments predeclared  in MUSBOX.  For a list of the available
instrument templates see where they are described on page 3.
They perform a variety of simple functions such as sinusoid generation,
fm, filtering, reverb, etc.  
They are able to use functions created by
Andy's SEG  record generating program,  SYS:TFUN (If  you
don't know about  this, some documentation is available in INTERM.TXT[DOC,MUS],
under the subject of FUNED and EDFUN, there is also in the program itself)
or Leland's FUNC program (see LCS).
Unlike MUSCMP (that is, NEWMUS and MUSIC and friends) instruments in MUSBOX
are capable of running more than one copy of themselves at a time.
When MUSBOX runs an instrument, it instantiates a  copy of the values
passed to that instrument for each time the instrument is called.
In essence, the code for each instrument is a "template" of the actual
instrument that is run.  In this way, if you want an instrument to play
two notes at the same time, the program SPROUTS two copies of this template,
keeping the values passed to the instruments from the PLAY block seperate
for each instantiation or sprout of the instrument template.
In short, overlapping the same instrument with itself will work (up to the
limit of  the  Samson box  hardware  = 256  oscillators,  128  modifiers).
Here's an example of an input file: (Reserved words are capitalized.)

PLAY;
SIMP 0 .5 A 1 F1 1 0 0 0;
FINISH;

	PLAY caused MUSBOX to begin looking for instruments to run.
You say PLAY when you want MUSBOX to start writing out commands, so it opens
an output file.  It uses the default output filename of TEST.SAM.  If you
with to call the output file something else, put the name after PLAY (e.g.
PLAY FOO; will cause the file FOO.SAM to be written).  SIMP is an instrument
predefined in the system version of MUSBOX, the numbers after it are the
things the instrument needs to know to play.  The meanings of these numbers
are relative to what the instrument expects to get, so you must consult
page 3 for a description of SIMP.
Bells and whistles for MUSBOX output.

Declarations, etc.:
------------------------------------------------------------------------
VARIABLE	takes a string of names as arguement, delimited by spaces
		and/or commas, which MUSBOX will treat as REALs.  (Everything in
		MUSBOX is handled as a REAL and only fixed when necessary.)  These
		variables are stored in a parallel array system,
		and can be used in any expression context such as 
		assignment statements,etc.
INSTRUMENT	takes a template name as its first argument then any number
		of other unique identifiers which will be associated with
		this template;
COMMON		same as INSTRUMENT, but someday INSTRUMENT will be redefined
		to cause MUSBOX to look up a .REL file full of instrument code
		and read it in.  At that time COMMON will be the only way
		to associate a template with a series of other identifiers
		that you want to also point to that template;
PLAY		begins a PLAY block.  May be followed with an optional argument
		specifying an output file, which will have the default extension
		".DOA" for SAMSON box output or ".PLA" for FRM output.  No
		filename defaultts to "TEST" plus extension.  Or, instead
		of a filename you can say "ASK" and MUSBOX will prompt the user
		at execution time and get the filename that way.
		Entering a PLAY block initializes lots of things as described
		below;
		It is legal to say PLAY inside a PLAY block (i.e., PLAY-FINISH
		do not really constitute a block boundary pair).  This does the
		same thing as resetting the pass counter to 0 (see below).  In
		this way it is possible to concatenate play lists.
FINISH		Ends a PLAY block, forces all instruments to quit, closes
		the output file.  An optional argument after the FINISH statement
		specifies the number of seconds to wait after the end of the
		last instrument before turning off the dacs and doing a reset;
RECORD		takes a filename with default extension ".FUN" and uses
		a special handler to read in SEG functions. Knows about "ASK";
INSERT		takes a filename with default extension ".SAM", suspends
		execution of current level, jumps to the new file and
		continues execution there, returning to this level when
		that is exausted.  Files can be inserted up to 15 deep.
		.FUN files can also be read in this way by adding the
		explicit extension. Knows about "ASK";
EXIT		forces MUSBOX to quit and returns you to the monitor, after
		closing all files, and runs SAMX with the output filename.
DONT_SCAN	stop scanning statements until you see:
SCAN		which turns scanning back on.  This is useful for making
		MUSBOX ignore part of the score.
************************************************************************

User settable variables to set before entering PLAY block:
	The following variables are tested by MUSBOX when it scanns a PLAY
statement to set overall conditions.  To have any effect, therefore, they
must be set before issuing the PLAY statement.
------------------------------------------------------------------------
boxtyp		assign either samdev or frmdev to determine the type of
		output.  This is also settable by
		having your input file have either extensions .SAM
		or .FRM respectively.
		defaults to samdev;
nptix		assign to how many processing ticks, defaults to 96;
nutix		assign to how many update ticks, defaults to 32;
ttix		total of the above two, this determines the sampling rate;
srate		will contain sampling rate calculated from nptix and nutix;
mag		will have frequency scaling calculated from srate;
pass		this is the pass counter, used to determine where we are in
		the flow of time.  It is basicly for use by wizards
		but the following can be done with impunity.  To reset the
		pass counter to 0 after a run of instruments so that the next
		run can start from zero again type after the first set PASS←0;
noutchans	assign between 0 and 4 output channels,
		defaults to quad;
whichside	assign 0 for dacs to read from generator sum memory only, 
		positive for modifier side only, negative for both sides,
		defaults to negative;
filters		for low pass filters on the dacs, assign any of these values:
			"unfiltered" ≡ bypass analog filters,
			0 ≡ 4.5 kHz
			1 ≡ 9.0 kHz
			2 ≡ 13.5 kHz
			3 ≡ 18.0 kHz,
		defaults to 3;
packing		set to left_justified, right_justified or full_word,
		defaults to full_word which is interpreted by LOWER to
		only load full_word when necessary;
optimization	set to optimize or non_optimize to determine whether
		LOWER will pack more commands per word where possible,
		defaults to non_optimize (this may change);
debug		assign with any summation of
		debug_instruments	to see what values they are passed,
		debug_scanning		to see what is read in from a file,
		debug_arithmetic	to see how MUSBOX does it's arithmetic,
		debug_stack		to see the contents of arithmetic stacks,
		debug_scheduling	to see how MUSBOX sprouts instruments;
************************************************************************

Variables preset by MUSBOX:
	All of the following are set up when you issue a PLAY statement.
They will not be assigned actual values until then!  These are writable
variables, so if you want to clobber them you can.  No guarantees, however
that doing so will get you anywhere.
------------------------------------------------------------------------
zero		predeclared sum memory location to always return zero;
outa, outb...d  predeclared sum memory locations to stuff generator output;
outma, outmb..d predeclared sum memory locations to stuff modifier output;
************************************************************************

Reserved procedures in MUSBOX:
	These claim and return the address of the next free sum memory 
location. They require initialization induced by the PLAY statement, and their
results are invalid outside a PLAY block.
------------------------------------------------------------------------
gen_sum		returns the next free last pass sum memory location;
mod_sum		likewise for modifiers;
print		prints the subsequent argument on the user's screen;
rdnum		returns a real number from the user;
getdm		takes length of delay memory desired as argument,
		returns base address if successful in claiming memory,
		else generates error(under development);
rand		returns a random number;
************************************************************************

Preloaded variables:
	These variables are set up when MUSBOX is entered and are valid
anywhere.  They are assigned the values indicated below them.
------------------------------------------------------------------------
A,AS,B,C,CS,D,DS,E,F,FS,G,GS;
440,466.16,493.89,261.62,277.18,293.66,311.13,329.63,349.23,369.99,391.99,415.31;
************************************************************************

Symbolic constants:
	These are predeclared symbols.  They cannot be assigned to,
but may be assigned from (e.g. a←pi, but not pi←a).
-------------------------------------------------------------------------
Generators:
g_inactive, g_pause, a_running, b_running, g_wait, c_running,
data_read, data_write, dac_write,
lplusq, lminusq, lexpplus, lexpminus,
sum_of_cosines, sawtooth, square, pulse_train, sine, sin_fm;

Modifiers:
m_inactive, u_noise, tr_u_noise, latch, threshold, invoke_delay_unit,
notwopoles, two_0poles, two_1poles,
notwozeroes, two_0zeroes, two_1zeroes,
int_mixing, one_pole, mixing, one_zero,
four_quad_multiply, am,
maximum, minimum, signum, zero_crossing_pulser,
add_sum_memory, replace_sum_memory;

Delay units:
delay, 
d_inactive,
delayline, table_lookup, round_table_lookup;

Debugging:
debug_instruments, debug_arithmetic, debug_scheduling, debug_scanning,
debug_stack,debug_records,debug_template;

Initialization:
samdev,frmdev,
unfiltered,
optimize,non_optimize,
right_justified,left_justified,full_word;

Misc. commands:
pause_clear,wait_clear;

Constants:
pi,
true,false;
************************************************************************
 
Misc. things:
------------------------------------------------------------------------
COMMENT	can be used to enter comments in the text, everything scanned
	until the first semicolon is seen will magically disappear;
<, ∂	these are also comment charactors and cause MUSBOX to flush the
	entire input line.  It does not break on a semicolon, but flushes
	everything until it sees a <crlf>. SO DON'T PUT ANY STATEMENTS YOU
	WANT TO HAVE EXECUTED ON THE SAME LINE AS "<" or "∂";
'	When this charactor is scanned at the beginning of a number
	the immediately subsequent value is presumed to be in octal.
↓	This charactor when used inside a PRINT statement will cause a
	<crlf> to be printed on the user's terminal;
ASK	When supplied as an argument anywhere that a filename is expected,
	MUSBOX will prompt the user for a filename instead of taking
	one from the file (e.g. PLAY ASK; at the head of a PLAY block
	will cause the filename handler to prompt the user.)
************************************************************************
The scanner-parser; file scanner.
	MUSBOX has an inverse Polish expression scanner that works in
the usual fashion.
Precedence of operators is:
    [")"]["¬"] unary negation
    ["↑"] exponentiation
    ["*"]["/"] ["⊗"] left shift
    ["+"]["-"] 
    ["("]["←"] 
Multiple operations of the same precedence are done left to right.

	MUSBOX has one filename handler for all the different kinds
of files it reads.  In all the modes that follow, it is possible to
put in any number of filenames (seperated by a comma or
space, or whatever) and they will be acted on in turn.  Additionally,
if the argument ASK is given instead of a filename, then MUSBOX will prompt
the user for the filename string. (This is not too useful at INPUT FILE
level obviously, but quite handy elsewhere, such as in the PLAY statement.)
	At INPUT FILE level, the default extension is .SAM, if that is not
found, then .FRM is tried.  There is no default device here, since a
<cr> does not look up a filename but prompts for TTY input.
This level can also be used to lookup function files if the .FUN extension
is explicitly added to the filename.  MUSBOX can be exited by typing <alt>
to the  INPUT FILE prompt.
	TTY input level is arrived at by typing a <cr> to INPUT FILE
level, which prompts with a ">".  To return to INPUT FILE level, type
<alt>. (The next <alt> would exit MUSBOX.) 
	FILE input level is when MUSBOX is snarfing down a file that
you pointed it to.  This level and TTY level are handled identically,
so whatever you say in a file you can also type in at a TTY and vice
versa.
	INSERT can be used when in TTY or FILE input levels to request
another file to be executed.  Execution of the new file(s) begins immediately.
It has the same defaults as INPUT FILE level.
	RECORD input statement accepts the default .FUN extension, otherwise
it behaves exactly like the other input modes.
	The PLAY statement takes an optional argument for the name
of the output .DOA file (DOA by the way stands for DataoA, now arn't you
glad you asked?) Default filename is TEST.DOA.  Additionally, saying
PLAY ASK; will prompt the user for an output filename.
Setting timing variables for Samson box output:
    You can now set any of srate, mag, ttix (total ticks), nptix
(number of processing ticks) or nutix (number of update ticks) and
the remainder of these variables will be set to reasonable values
(it sez here).  Hence, you can say srate←25600; and the right things
get done to accomplish that.  However, do not try to reset any of
these variables inside a play block, as unpredictable things (bugs)
will happen.  This should be fixed in the near future (1/31/78).
    Additional warnings:  The "right thing" may not always be
unambiguous, and MUSBOX does what it can.  For instance, simply
setting ttix does not specify the division between nptix and nutix,
so this is defaulted to a rather arbitrary ratio between the two
(3/1).  This ambiguity can be overcome by setting nptix and nutix
yourself, but letting MUSBOX do it should be ok most of the time.
    Also, since the thing that really determines the sampling rate
is the integer ttix, setting srate (which is a real) will give you
instead the srate calculated from the nearest integer value of ttix.
Everything else is set from this also.  So if the srate you get is
not exactly the srate you set, that's why.

    Processing ticks are restricted to be ≥2 and ≤256.
    Update ticks are restricted to be ≥2.
    Total ticks are always 8 more than the sum of update and processing
ticks (to account for overhead ticks).

    The numbers actually compiled into the DOA command stream
will be slightly different, reflecting how the box likes to think
about these things, that is:
    Highest tick will be ttix-2.  This is because the counter must
start at 0, and be one less than the number required (see the spec.).
    Highest proc. tick will be nptix-1 also because counter must start
at 0, again as per spec.
PRINT statement, strings, RDNUM.
	There is a print statement that you can do all sorts of 
bizarre things with such as:

PRINT "now replace a with b",a←b;
PRINT -(1/(2↑.5)*pi,"look ma no hands",1 ⊗ 20;

	PRINT also works for getting information about functions.
PRINT amp1
will give you its type, where it is on the list, the number of elements,
etc.
	The charactor "↓" is reserved in MUSBOX and prints out
a carriage return - linefeed on the users terminal.  Strings 
must be surrounded by quotes, quotes within quotes are not supported.
(A hidden benefit of the string implementation is that you can
surround anything in quotes and it will magically dissapear except
when it is inside a PRINT statement, i.e., it acts just like a COMMENT:
"now replace a with b"a←b;).

	RDNUM takes a string argument from the user and returns
it to MUSBOX.  The following asks for a number and deposits it in A;
PRINT "Type your mother's birthdate",↓;
A←RDNUM;
Even less about loading Samson box command streams
THIS IS OBSOLETE, R SAMX INSTEAD.
There are two things you can do with the output of MUSBOX (that I know of)
namely disassemble it to see if it looks reasonable, or play it to
see if it sounds reasonable.
	Playing the commands currently requires that you make up a realtime
job to be loaded on the SIX that actually runs SAM.  The best way to do this
is to not ask any questions, but to make a DO file called something
like CVSND.DO that looks like this:

ru cvos↔?a.doa↔?a.str↔loa ?a←rehead.rtj+?a.str+tail.rtj↔r ten↔?a↔

Then you need the sources of the things the DO file will call.  So copy into
your area the following files:
	cvos.dmp[sam,mus],
	rehead.rtj[sam,dgl],
	tail.rtj[sam,dgl].

Then type to the monitor:
.DO CVSND
to which it will respond:
  a=	_
to which you respond (in this case):
foo<cr>
It will then go away and print various things on your screen and eventually
come back to ask you to type <cr> to start job.  Do so and follow instructions.
Typing <alt> will exit this program.

	Disassembly is done with Mark Kahrs' program DAB (a lil' dab'l  do
ya') which stands for DisAssemble the Box.  You take the command file,  in
this case FOO.doa, and

.r dab
input file: foo.doa
output file: foo.dab

↑C
.
et foo.dab/r

and this is what you get (egads!): (please note, these opcodes may not be correct!)

0       20000005001     GFM     0           1               ;fm address
1       15401           GO      1           1               ;sweep rate
2       10400005001     GMODE   200         1               ;mode dac l+q sum
3       1400600         HiProc  140                         ;Highest Proc Tick
4       2000610         HiTick  200                         ;Highest Tick
5       10000005002     GMODE   0           2               ;mode inactive l+q sum
6       20000004002     GSUM    0           2               ;sum memory
7       5402            GO      0           2               ;sweep rate
8       314022002       GJr     31402       2               ;frequency
9       20000005002     GFM     0           2               ;fm address
10      10000004002     GL      0           2               ;asymptote
11      1002            GQr     0           2               ;decay exponent
12      3002            GP      0           2               ;delta
13      4402            GK      0           2               ;angle
14      20000003402     GM      0           2               ;scale
15      10000003402     GN      0           2               ;ncosines
16      13610005002     GMODE   1704        2               ;mode a_run l+q cos
17      10000005003     GMODE   0           3               ;mode inactive l+q sum
18      20000004003     GSUM    0           3               ;sum memory
19      5403            GO      0           3               ;sweep rate
20      154052003       GJr     15405       3               ;frequency
21      20000005003     GFM     0           3               ;fm address
22      10000004003     GL      0           3               ;asymptote
23      1003            GQr     0           3               ;decay exponent
24      3003            GP      0           3               ;delta
25      4403            GK      0           3               ;angle
26      20000003403     GM      0           3               ;scale
27      10000003403     GN      0           3               ;ncosines
28      13610005003     GMODE   1704        3               ;mode a_run l+q cos
29      3002            GP      0           2               ;delta
30      1002            GQr     0           2               ;decay exponent
31      3003            GP      0           3               ;delta
32      1003            GQr     0           3               ;decay exponent
33      6070420         Dwell   607                         ;Dwell (Linger)
34      3002            GP      0           2               ;delta
35      20550420        Dwell   2055                        ;Dwell (Linger)
36      3002            GP      0           2               ;delta
37      60400420        Dwell   6040                        ;Dwell (Linger)
38      3002            GP      0           2               ;delta
39      61640420        Dwell   6164                        ;Dwell (Linger)
40      3003            GP      0           3               ;delta
41      105550420       Dwell   10555                       ;Dwell (Linger)
42      3002            GP      0           2               ;delta
43      121700420       Dwell   12170                       ;Dwell (Linger)
44      3002            GP      0           2               ;delta
45      1002            GQr     0           2               ;decay exponent
46      210070420       Dwell   21007                       ;Dwell (Linger)
47      3003            GP      0           3               ;delta
48      613010420       Dwell   61301                       ;Dwell (Linger)
49      3003            GP      0           3               ;delta
50      1067500420      Dwell   106750                      ;Dwell (Linger)
51      3003            GP      0           3               ;delta
52      10000005004     GMODE   0           4               ;mode inactive l+q sum
53      20000004004     GSUM    0           4               ;sum memory
54      5404            GO      0           4               ;sweep rate
55      630042004       GJr     63004       4               ;frequency
56      20000005004     GFM     0           4               ;fm address
57      10000004004     GL      0           4               ;asymptote
58      1004            GQr     0           4               ;decay exponent
59      3004            GP      0           4               ;delta
60      4404            GK      0           4               ;angle
61      20000003404     GM      0           4               ;scale
62      10000003404     GN      0           4               ;ncosines
63      13610005004     GMODE   1704        4               ;mode a_run l+q cos
64      1110700420      Dwell   111070                      ;Dwell (Linger)
65      3004            GP      0           4               ;delta
66      1004            GQr     0           4               ;decay exponent
67      1232600420      Dwell   123260                      ;Dwell (Linger)
68      3003            GP      0           3               ;delta
69      1003            GQr     0           3               ;decay exponent
70      1554270420      Dwell   155427                      ;Dwell (Linger)
71      3004            GP      0           4               ;delta
72      2545240420      Dwell   254524                      ;Dwell (Linger)
73      3004            GP      0           4               ;delta
74      5520130420      Dwell   552013                      ;Dwell (Linger)
75      3004            GP      0           4               ;delta
76      7502050420      Dwell   750205                      ;Dwell (Linger)
77      3004            GP      0           4               ;delta
78      10606000420     Dwell   1060600                     ;Dwell (Linger)
79      3004            GP      0           4               ;delta
80      1004            GQr     0           4               ;decay exponent
81      0               Noop                                ;Misc No effect
Loading your own instruments.
(This is currently under development, sorry for the inconvienience,
I hope construction will be done shortly, but meanwhile, pardon
my dirt!)

	Currently there is only one way to do this, by using
the system loader to load in your instruments with the MUSBOX scanner.

MUSBOX figures out from the INSTRUMENT statement what template
to associate with what set of instrument names.  The template
name in the INSTRUMENT definition is matched up against a list of
preloaded template names, and the right instrument template procedure
(the one that does the actual stuffing of commands) is called
by using the number of the array element where this template name
is found in the template table.  It takes this number and uses
it in a case statement to figure out which procedure to call.
The actual calling of the procedure is done in InsCal.
The names of the procedures in the InsCal case statement are named
Ins0 through Ins17.
	If you don't want to use the predeclared instrument template
names (likely, if you are rolling your own) then you can overwrite
the default names using the TEMPLATE declaration.  The set of
names following the declaration will then become the only template
names available and they will be matched up starting from
Ins0.

Your instrument template should look like this:
	(color this in SAIL)

∂17-Feb-78  0316	JOS  	MUSBOX
What is necessary to increase the number of allowed instruments in MUSBOX?
I only have 2 slots left ( assuming ins14 is the last, 3 if ins15 is last ).
I need room to play around with the filters in my own version of MUSBOX.
Also, I notice that when an instrument is named twice in score ( overlapping ),
only the most recent invocation makes it through. Is this the way things are
supposed to be ?
In general, however, MUSBOX is doing everything right...HOORAY!

[DGL - ins15 is the last in the current version.  
To increase the number of instruments would involve the following
three steps:
	1) In SAMINS.SAI, change the upper boundary of the template
identifier table, "tplLen" to the desired size.  Add string preload
identifiers to correspond to the procedures to be added.  Change the
pointer to the end of the preloaded table, "preLdTemplateLen" to equal the
highest number of instrument you will use (typically it will equal the
length of the array).  The pointer to the end of the preloaded table,
"tplPtr" is initialized from preLdTemplateLen, and the array is scanned
from end to beginning.  Here is the relevant code from
SAMINS.SAI[SAM,DGL].  Presumably you would be making these changes to a
copy of your own.  The subtract 1 in the following example is because
tplIds goes from 0.

define tplLen="17-1";
define preLdTemplateLen="17-1";
preload_with "GOSC","GOSCVF","SHAPE","LINGER","GEN","MOD","MIX","RANDOM",
"FILTER","REV","GENFM1","GENFM3","NGEN","SPACE",NULL,NULL,
"FRMINS"
;
string array tplIds[0:tplLen];


	2) Add the procedures to your file of instruments, declaring
them INTERNAL.  Add them also on page 2 of MUSBOX declaring them EXTERNAL.

	3) Add the procedures to the CASE statement in InsCal
on page 7 of MUSBOX.

The slot corresponding to ins16 is a dummy corresponding to FrmIns.
It is a dummy because FrmIns is called seperately from the instruments
in SAMINS.  It is called only when the variable boxTyp equals the
macro frmDev.  So you can clobber "FRMINS" on the preload table with
impunity and as long as boxTyp≠frmDev (the usual case) SAMINS ins16 will
be called (presuming that you've taken the trouble to put one out there).

	What could be simpler!?!...
	-Gareth]
Loading MUSBOX
	I try to keep the most recent export version of MUSBOX.SAI on
[SAM,MUS], but if that one doesn't work, try MUSBOX.OLD[SAM,DGL].
The version under development is usually MUSBOX.SAI[SAM,DGL].
The old dump from the system is kept in MUSBOX.OLD[SAM,MUS].

	To get a copy of MUSBOX for your very own, copy onto your
area the following files from [SAM,MUS]:
	MUSBOX.SAI,
	MUSBOX.HDR,
	SAMTBL.SAI
	SAMINS.SAI,
	PRSNAM.REL,
	FRMINS.REL, if you intend to do FRM output,
If you have made changes to SAMINS or MUSBOX or anything else, the
way to recompile is any or all of the following:
	1) Changed only MUSBOX.SAI and/or MUSBOX.HDR and/or SAMTBL.SAI:
.load MUSBOX/sav
	2) Changed only SAMINS.SAI, didn't touch any files in (1):
.com SAMINS
.loa MUSBOX/rel/sav
	3) Changed any of INTERM.SAI, LOWER.FAI [SAM,MUS]
.loa MUSBOX/rel/sav
Since these are the most popular things to diddle with, I'll leave
the explication to that.

How it all hangs together:
	MUSBOX.SAI requires the following files:
    require "MUSBOX.HDR" source_file;
    require "SAMTBL.SAI" source_file;
    require "SAMINS.REL" load_module;
    require "PRSNAM.REL" load_module;
  ∂ require "FRMINS.REL" load_module;
The "∂" comment charactor must be removed from in front of every
mention of FRMINS in MUSBOX.SAI to enable MUSBOX to do FRM output.
You must then recompile MUSBOX.SAI.
	MUSBOX.HDR in addition calls the following files:
    require "INTERM.HDR[SAM,MUS]" source_file;
    require "SEGSYN.REL[MA,JAM]" load_module;
    require "SYS:RECORD.DEF" source_file;
	INTERM.HDR in turn calls:
    require "INTERM.REL[SAM,MUS]" load_module;
    require "SYS:PROCES.DEF" source_file;
    require "LOWER.DEF[SAM,MUS]" source_file; 
    require "LOWER.REL[SAM,MUS]" load_module; 
So altogether there are 12 files called by MUSBOX itself!  Quite
a list...  There is a hierarchical division of MUSBOX into
three levels.  The "lower" level code assembles the command stream
to the Samson box.  It also has a processing element allocation
scheme and contains tables and flags relating to the actual machine
architecture of the box.  The "intermediate" level code groups the
routines of the lower level into bitesize chunks that do complete
functions, such as reverberation, complex fm instruments, etc.
The third level is MUSBOX itself which is the scanner/parser that
is used to drive the lower levels.
The essential ingredients in an instrument file
	An instrument file or MBOX consists of the following three
parts: 
	1) A page of specific external declarations and require statements
that can be found in INSHDR.SAI[SAM,MUS].  These go at the beginning of the
instrument file.  For an example file, see page 2 of TSTINS.SAI[SAM,MUS].
	2) The code for the instrument(s), see page 3 of TSTINS.SAI.
	3) A final page with a procedure that will link all the instruments
together when MBOX is run, see page 4 of TSTINS.SAI.
	While this example is of only one instrument, any number can
be used.  For an example of multiple instruments, see SAMINS.SAI[SAM,MUS],
especially the penultimate page where the procedure MakeInstrumentLinkedList
is defined.  Notice there is one call to LnkIns within that procedure
for each instrument that is to be loaded.
	The instrument is compiled either by saying to the monitor:
.COMpile <instrument_file_name>.sai
or by using a special dump of the SAIL compiler designed for compiling instruments
called INSHDR.DMP[SAM,MUS].  Using this special compiler has the effect of
saving a considerable amount of compute time.
To use this facility requires the following
actions:
	First, copy to your area the file INSHDR.REL[SAM,MUS]. Then
do the following sequence: (your actions in lower case)

.ru inshdr[sam,mus
*samins←tstins
TSTINS.SAI 3
COPYING DSK:INSHDR.REL
 1 2 3 4 ...
*↑C
↑C
.
Things available to instrumens from MBOX.
    external procedure BoxError(string errmsg);
    external boolean procedure getRecord(string name; 
	reference record_pointer(any_class) r; record_pointer(any_class) Tops);
    external procedure LinkUp(
	    reference record_pointer(any_class) lstTop;
	    Record_Pointer(any_class) lstTmpTop;
	    integer lstTyp(functionList));
    external record_pointer(InsCls) insTop;
    External real srate,mag;
    debugFlag(flag,testBits)= ⊂(flag div 1 land testBits)⊃;
What each instrument is handed by the scanner
	A record pointer is passed to the instrument which points
to a record.  The record contains all the information that the scanner
has about this instantiation of the instrument.  It includes the
following:
    1) Two parallel arrays, one real, the other of type record_pointer(any_class).
These arrays contain all the fields that the scanner found for this instrument
from P0 out to the current length of P32.  The real array contains
the values parsed from arithmetic expressions, the record_pointer array
contains record pointers to the SEG functions to be used by the instrument
for such things as amplitude and frequency control through time.
	For instance,
if the scanner saw a PLAY list that looked like this:
PLAY;
SIMP 0 1 A AMP1 1 0 A_RUNNING+LPLUSQ+SINE 0 ZERO OUTA;
FINISH;
(where SIMP is the name of an instrument, A is a predeclared variable
that returns the value 440, and A_RUNNING, LPLUSQ and SINE are also
predeclared variables which, when summed are a complete specification of
a running mode for a generator, ZERO and OUTA are predeclared variables
containing the addresses of sum memory locations,
and finally, AMP1 is a SEG function that has been read in from a file),
then the first ten fields of the 32 fields presented to the instrument
on the two parallel arrays will be as follows:

array element number:
0	1	2	3	4	5	6	7	8	9	10
value in real array:
X	0.	1.	440.	0.	1.	0.	976.	0.	448.	384.
value in record_pointer array:
SIMP	Y	Z	nr	AMP1	nr	nr	nr	nr	nr	nr.
	We see that only one SEG record was passed to this instrument in P4 
(nr is used here to mean "null_record", i.e., no record is being pointed to).
A record_pointer to SIMP shows up in P0 of the record_pointer array.
What this means is, that using this you can access the linked list of instruments
and find out what is there, and from there can examine any link on that list.
This is useful for instruments that interact with one another.
On the real array,
the sum of the three running mode symbols totals 976, which is a proper running mode,
448 and 384 are valid sum memory locations corresponding to ZERO and OUTA.
These numbers for modes and sum memory locations are passed to LOWER which
decodes them and makes up commands.
	The remaining 22 fields in these parallel arrays will be meaningless
for this instrument and may contain values left over from previous calls to
this or other instruments (believe it or not, that's a FEATURE!).
	The meaning of X, Y and Z above is this: these are locations that
are unusable in the normal sense, so we can use them for special things.
	To wit, P1 and P2 are required to be arithmetic expressions that yield
a begin time and a duration.  Thus no record_pointers can occupy those
positions.  So instead, location Y is used to pass the address of the head
of the linked list of all SEG functions.  Thus you can actually get at any
SEG function that has been read in, if you want to.  There is a procedure
available to you to facilitate this called GetRecord (see previous page)
which, when passed this head record_pointer and the string name of the record
on the list you wish to get at, it returns a record_pointer to that record.
The Z array element on the record_pointer array is currently unused, but
is reserved for future expansion (having to do with interactive instruments).
	The X location on the real array has a similar story.  Since P0 is
reserved for the record_pointer to the instrument linked list, no number
can occupy P0.  So instead, a debug flag is placed there which the instrument
can interpret.  The debug flag starts out life in the scanner as an integer,
and is passed to the instrument on this real array.
When a user says soething like 
DEBUG←DEBUG_INSTRUMENTS;
to the scanner, the scanner turns on a certain bit in the debug flag.
An instrument can subsequently test to see if this bit is on, and if it is,
can then do various things, such as print out to a teletype the values
it was passed so the user can see if they agree with what he thinks should
be there.  There is a macro to facilitate testing the debug flag, called
(appropriately) debugFlag (see previous page).  It's use in the instrument
example should suffice for an example.
GOSC GOSCVF SHAPE LINGER GEN MOD MIX RANDOM FILTER REV GENFM1 GENFM3 SPACE

These are the formal calls to the instruments that are preloaded in the
system version of MUSBOX.
	Beg	-begin time in seconds
	Dur	-duration in seconds
	Freq	-frequency in Hz.
	ampRec	-name of amplitude function found in a function file that
		has been read in using the RECORD statement.
	ampScl	-scale factor for amplitude (0 ↔ 1).
	ampOff	-DC offset for the amplitude envelope (0 ↔ 1).
	frqScl	-scale factor for frequency function (0 ↔ srate/2).
	frqOff	-offset for the frequency function (0 ↔ srate/2).
	Mode	-generator or modifier running mode (see LRNSAM).
	Ncs	-number of cosines, for generator sum_of_cosines mode, else 0.
	fmSum	-sum memory read addr. for FM input to a generator.
	outSum	-sum memory write addr. for generator or modifier output.

∂ GOSC - fixed frequency, seg record variable amplitude;

∂ sample call:
    <instrument> Beg, Dur, Freq, ampRec, Ampscl, Ampoff, Mode, Ncs, Fmsum, outsum;

∂ GOSCVF - seg record variable frequency and amplitude;

∂ Sample call in an MUSBOX play list:
    <instrument>, beg, dur, frqRec, Frscl, Froff, ampRec, Ampscl, Ampoff,
    Mode, Ncs, Fmsum, Outsum;

∂ SHAPE - apply an envelope to a signal of amp up to 8.0;

∂ Sample call:
    <instrument> beg,dur,ampRec,scale,offset,outadr,inadr,factor;

∂ LINGER;

∂ sample call:
    <instrument> beg dur;

∂ GEN - raw call to a generator;

∂ sample call:
    <instrument> Beg, Dur, Freq, Sweep, Angle, nCos, Scale, 
    Asym, Rate, Exp, Mode, Fmsum, Outsum, GenNum;
∂ Please note: this instrument simply passes whatever you put in the P
  fields to LOWER, it does no scaling by MAG or anything whatsoever.
  The only thing that is not just passed blindly to LOWER is the field
  GenNum, which, if GenNum>0, will claim the so-numbered generator,
  else it will take first available one that LOWER gives it.
;
∂ Mod - raw call to a modifier, no scaling of any terms;

∂ sample call:
    <instrument> beg dur cf0 cf1 trm0 trm1 ain bin outloc ascl bscl mode modnum;
∂ If modNum>0 then claim that modifier, else take the first that's available;

∂ MIX - Multiply two signals by a constant factors between 0 and 8.

∂ sample call:
    <instrument> beg dur factor1 factor2 in1loc in2loc outloc;

∂ RANDOM - Make random numbers scaled by a factor;

∂ sample call:
    <instrument> beg dur factor trigger seed outloc;

∂ FILTER - Does one or two pole or zero fixed character filtering.

∂ sample call:
    <instrument> beg dur frq R second_order all_pole inloc outloc;

∂ REV - Reverberator. Can be all-pass or comb.
To make an allpass, set g1←-g0←G;

∂ sample call:
    <instrument> beg dur length g0 g1 inloc outloc;

∂ GENFM1;

∂ sample call:
    <instrument> Beg, Dur, Freq, ampRec, Ampscl, Ampoff, 
    Mode, Ncs, cfmfRatio, indexRec, index, indexOff, outsum;

∂ GENFM3;

∂ sample call:
    <instrument> Beg, Dur, Freq, ampRec, Ampscl, Ampoff, Mode, Ncs, 
    cfmfRatio1, indexRec1, index1, indexOff1,
    cfmfRatio2, indexRec2, index2, indexOff2,
    cfmfRatio3, indexRec3, index3, indexOff3,
    outsum;

∂ NGEN;
∂ sample call:
    <instrument>,beg,dur,mode,outSum,nFuncs,
	frNameN,frSclN,frOffN, ampNameN,ampSclN,ampOffN;
∂   where: frNameN is a record function string name which can look like
	either of these: foo1 or foo4a1, etc., i.e., it must
	begin with a letter and end with a digit.  This will be taken,
	and the first of the series looked up and the number of them
	specified in p5 will be used in the synthesis;

∂ SPACE;
∂ <instrument> beg dur nChans qRecN inLoc revOut %Rev
	outLoc1 outLoc2 outLoc3 outLoc4;
∂ nChans can have a range of 0 to 4, 4 being the usual case;
∂ Output locations must be on modifier side sum memory, usually outMa→d;
∂ revOut is a sum  memory location (on modifier  side) that will have  the
signal scaled by grev which is to be fed to the reverberators that  supply
the global reverb to outMa→d;
∂ %Rev is the fraction of the direct signal to be sent to the reverberators;
∂ qRecN is a record function name described as
<group_name>&|"grev"|"lrev"|"amp"|"dop"|"chan1"|"chan2"|"chan3"|"chan4",
where the group_name is typically the same as the file which contains the
whole set, but can be anything, and the vertical bar seperates the various
functions that make up a set of quad functions.  For example, if the group
name for a set of functions is "Circle", then the global reverb function
of that group is "CircleGrev".  (Note:  if the function name is
"circle_grev", the group name will be interpreted as being "circle_".)
All you need to specify in the play list is any one of the set of names
and it will find all the rest of the functions it wants by parsing out
the group_name, then searching for the individual functions using this
name;
∂ This instrument has no provision for local reverb (lrev);


∂ RESF;
∂ sample call:
    <instrument> beg dur R minF maxF Ffun all_pole inloc outloc spacing
		  1   2  3  4    5    6      7       8     9	 10
	where 0≤r≤1, minF and maxF are in Hz, all_pole is true or false(all_zero).
	Spacing is # of samples between update commands.
	Warning, the gain of this filter is unnormalized!  The usual thing
	to do about that is to first put the input to the filter through
	a MIX or SHAPE with amplitude scaling equal to 1-r.  This should
	guarantee that the filter doesn't overflow at resonance.
	A good value for spacing depends on how much the function jumps
	around, but for slow moving functions = srate/100, fast = srate/10000;
That's about all you need to know.  If you have any questions, 

I just stepped out...
 
 
APPENDIX - Running out of Sum_Memory Locations on the Generator Side [JEG]

The maximum number of sum_memory locations are 68 on each the generator 
and modifier  side. Problems may  occur - even with simple instruments  -
if there is a constant overlapping of  notes in one voice which is  moving
rapidly. Let's presume you have a simple FM instrument; that requires  one
sum_memory location for  the modulating  frequency (which is  read by  the
following generator) and one for  the modulated frequency (which may  then
be further processed by reverb etc.). If  each note is to have a  constant
duration of 3 sec. and  the voice is moving in  16th at MM=120, (so a  new
note will start every  .125sec), MUSBOX will  claim 48 different  sum_memory
locations on the generator  side before it will  release the first two  it
claimed for the first 16th note.

Total number of sum_mem.loc/gen.side = number of gen_sum_mem.loc used
inside the recursive instrument  call * (constant  duration / duration  of
rhythmical value).  Applied to the presumed case: 2 * ( 3 / .125 ) = 48.

Obviously you will be in trouble if there are only two voices going on  at
the same time in 16th notes - you'll need 96 locations.

Two steps to tackle  the problem:  cut down  on the constant duration  and
leave a little work for the  reverb (which naturally doesn't quite do  the
job, because  it is  distributing to  all  channels and  not just  to  the
location  of  the  sound  source)  and,  secondly,  get  rid  of  claiming
sum_memory laocations inside the recursive procedure as much as possible.

The outlocation of the modulating generator has to be a new one for  every
call, as the modulating frequency  depends on the carrier frequency  which
may be a new one  for every note. But the  outlocation of the final  sound
can be  taken out  of the  recursive procedure  and be claimed in  the
header file, so one voice always writes into the same location even though
the instrument is overlapping and getting set up anew for every call.  So:
in your header file you declare let's say the variable "outins"; then  you
assign a sum_memory location/gen.side to that variable after the PLAY  ASK
statement: "outins←GEN_SUM;". In your instrument file you put a locPns[xy]
where the final outlocation of the instrument is required and in all other
cases where the final sound is to be treated, e.g. in a mixer in which  it
gets scaled with a distance function.  In your score file locPns[xy]  gets
"outins".

Now every sample of this voice writes out into the same gen_sum; so,  when
overlapping, the rest of the one note writes into the same location as the
beginning of the  following note.  It  does not claim  a new location  for
every note, as it would have done before.

The trade off: since the rest of  one note coincides with the beginning  of
the next note, both get treated in the same way by a localization  process.
Thus you may  get a  discontinuity if e.g.   the first  note is  localized
infront of you  and the second  note in your  back. Now the  dacay of  the
first note will come from the  point where the second note starts  instead
of coming  from the  point where  it started.   When doing  small  spatial
progressions it should  not matter. The  problem of spatial  jumps can  be
overcome by using two gen_sum locations for one voice; the first note gets
the first outloc, the second the  second, the third the first, the  fourth
the second etc, so the discontinuity won't be that harsh, since the  decay
of each note will have come closer to 0 when it gets pushed away.

If you are using different spatial movements independently for every voice,
you naturally have to set up a different gen_sum for each voice.

							[JEG]
If you want your instrument to have a default F1 function like MUSCMP,
then put this code somwhere in your instrument file (like maybe the last page).

internal record_pointer(any_class) array rPrms[0:prmLen];  

procedure MakeF1;
    begin
    record_pointer (any_class) foo;
    foo←New_Record(seg);
    newArray(real,seg:times[foo],[1:4]);
    newArray(real,seg:values[foo],[1:4]);
    seg:name[foo]←"F1";
    seg:type[foo]←0;
    seg:maxval[foo]←1;
    seg:minval[foo]←0;
    seg:maxtime[foo]←100;
    seg:mintime[foo]←0;
    seg:nsegs[foo]←4;
    seg:times[foo][1]←0;
    seg:times[foo][2]←25;
    seg:times[foo][3]←75;
    seg:times[foo][4]←100;
    seg:values[foo][1]←0;
    seg:values[foo][2]←1;
    seg:values[foo][3]←1;
    seg:values[foo][4]←0;
    Linkup(top,foo,functionList,false);
    RPrms[5]←foo;
    end;
require MakeF1 initialization;
If you want to preset the P fields in MBOX to default values,
then do something like this, and put it on or about the last page
of your instrument file.

procedure SetupPns;
begin
 ∂  SIMP Beg, Dur, Freq, ampScl, ampRec, outAamp,outBamp,outCamp, outDamp;
 ∂    0,   0,  .5,  440,     .3,      0,     1.0,    1.0;
$prms[2]←.5;	sPrms[2]←".5";
$prms[3]←440;	sPrms[3]←"440";
$prms[4]←.3;	sPrms[4]←".3";
$prms[6]←1;	sPrms[6]←"1";
$prms[7]←1;	sPrms[7]←"1";
end;
require SetupPns initialization;